home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 1.iso / toolbox / src / exampleCode / opengl / GLUT / test / bigtest.c < prev    next >
C/C++ Source or Header  |  1996-11-11  |  57KB  |  2,584 lines

  1.  
  2. /**
  3.  * My first GLUT prog.
  4.  * Uses most GLUT calls to prove it all works.
  5.  * G Edwards, 30 Aug 95.
  6.  *
  7.  * Notes:
  8.  * Display lists are not shared between windows, and there doesn't seem to be
  9.  *  any provision for this in GLUT. See glxCreateContext.
  10.  *
  11.  * The windows are internally indexed 0,1,2,3,4,5,6. The actual window ids
  12.  * returned by glut are held in winId[0], ...
  13.  *
  14.  * Todo:
  15.  *
  16.  * Could reorder the windows so 0,1,2,3,4,5,6 are the gfx, 7,8 text.
  17.  *
  18.  * 30 Aug 95  GJE  Created. Version 1.00
  19.  * 05 Sep 95  GJE  Version 1.01. 
  20.  * 07 Sep 95  GJE  Version 1.02. More or less complete. All possible GLUT
  21.  *                 calls used, except dials/buttons/tablet/spaceball stuff.
  22.  * 15 Sep 95  GJE  Add "trackball" code.
  23.  *
  24.  *  Calls not used yet: these callbacks are registered but inactive.
  25.  *
  26.  *  glutSpaceball<xxx>Func
  27.  *  glutButtonBoxFunc
  28.  *  glutDialsFunc
  29.  *  glutTabletMotionFunc
  30.  *  glutTabletButtonFunc
  31.  *
  32.  * Tested on:
  33.  *  R3K Indigo Starter
  34.  *  R4K Indigo Elan
  35.  *  R4K Indy XZ
  36.  *  R4K Indy XL
  37.  *  R4K Indigo2 Extreme
  38.  */
  39.  
  40. #include <GL/glut.h>
  41. #include <stdio.h>
  42. #include <stdlib.h>
  43. #include <string.h>
  44. #include <unistd.h>
  45.  
  46. /* Missing datatypes */
  47.  
  48. #define Boolean GLboolean
  49. #define TRUE    GL_TRUE
  50. #define FALSE   GL_FALSE
  51.  
  52. /* Controls */
  53.  
  54. #define VERSION    "1.00"
  55. #define DATE       "16Sep95"
  56. #define DELAY      1000 /* delay for timer test */
  57. #define MENUDELAY  200  /* hack to fix glutMenuStateFunc bug */
  58. #define MAXWIN     9    /* max no. of windows */
  59.  
  60. int AUTODELAY = 1500;   /* delay in demo mode  */
  61.  
  62. #define VERSIONLONG "Version " VERSION "/" DATE ", compiled " __DATE__ ", " __TIME__ ", file " __FILE__
  63.  
  64. int pos[MAXWIN][2] =
  65. {
  66.   {50, 150},            /* win 0  */
  67.   {450, 150},           /* win 1  */
  68.   {50, 600},            /* win 2  */
  69.   {450, 600},           /* win 3  */
  70.   {10, 10},             /* subwin 4 (relative to parent win 0) */
  71.   {300, 400},           /* help win 5  */
  72.   {850, 150},           /* cmap win 6  */
  73.   {850, 600},           /* cmap win 7  */
  74.   {250, 450}            /* text win 8  */
  75. };
  76.  
  77. int size[MAXWIN][2] =
  78. {
  79.   {350, 350},           /* win 0  */
  80.   {350, 350},           /* win 1  */
  81.   {350, 350},           /* win 2  */
  82.   {350, 350},           /* win 3  */
  83.   {200, 200},           /* subwin 4  */
  84.   {700, 300},           /* help win 5  */
  85.   {350, 350},           /* cmap win 6  */
  86.   {350, 350},           /* cmap win 7  */
  87.   {800, 450}            /* text win 8  */
  88. };
  89.  
  90. /* Macros */
  91.  
  92. #define PR     if(debug)printf
  93. #define PR2    if(TRUE)printf
  94.  
  95. /* #define GLNEWLIST(a, b)  glNewList(a, b), fprintf(stderr,
  96.    "creating list %d \n", a); */
  97. /* #define GLCALLLIST(a)    glCallList(a), fprintf(stderr,
  98.    "calling list %d \n", a); */
  99. /* #define GLUTSETWINDOW(x) glutSetWindow(x), fprintf(stderr,
  100.    "gsw at %d\n", __LINE__) */
  101.  
  102. /* Globals */
  103.  
  104. int winId[MAXWIN] =
  105. {0};                    /* table of glut window id's  */
  106. Boolean winVis[MAXWIN] =
  107. {FALSE};                /* is window visible  */
  108.  
  109. Boolean text[MAXWIN] =
  110. {FALSE};                /* is text on  */
  111. Boolean winFreeze[MAXWIN] =
  112. {FALSE};                /* user requested menuFreeze  */
  113. Boolean menuFreeze = FALSE;  /* menuFreeze while menus posted  */
  114. Boolean timerOn = FALSE;  /* timer active  */
  115. Boolean animation = TRUE;  /* idle func animation on  */
  116. Boolean debug = FALSE;  /* dump all events  */
  117. Boolean showKeys = FALSE;  /* dump key events  */
  118. Boolean demoMode = FALSE;  /* run automatic demo  */
  119. Boolean backdrop = FALSE;  /* use backdrop polygon  */
  120. Boolean passive = FALSE;  /* report passive motions  */
  121. Boolean leftDown = FALSE;  /* left button down ?  */
  122. Boolean middleDown = FALSE;  /* middle button down ?  */
  123.  
  124. int displayMode = GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH;
  125. int currentShape = 0;   /* current glut shape  */
  126. int scrollLine = 0, scrollCol = 0;  /* help scrolling params  */
  127. int lineWidth = 1;      /* line width  */
  128. float angle = 0.0;      /* global rotation angle  */
  129. char *textPtr[1000] =
  130. {0};                    /* pointers to text window text  */
  131. int textCount = 0, helpCount = 0;  /* text list indexes  */
  132. float scaleFactor = 0.0;  /* window size scale factor  */
  133.  
  134. #ifdef ALPHA
  135. #undef ALPHA  /* Avoid problems with DEC's ALPHA machines. */
  136. #endif
  137.  
  138. int menu1, menu2, menu3, menu4, menu5, menu6 = 0, menu7, menu8;
  139. enum {
  140.   RGBA, INDEX, SINGLE, DOUBLE, DEPTH, ACCUM, ALPHA, STENCIL, MULTISAMPLE,
  141.   STEREO, MODES
  142. };
  143. char *modeNames[] =
  144. {"RGBA", "INDEX", "SINGLE", "DOUBLE", "DEPTH", "ACCUM",
  145.   "ALPHA", "STENCIL", "MULTISAMPLE", "STEREO"};
  146. int glutMode[] =
  147. {GLUT_RGBA, GLUT_INDEX, GLUT_SINGLE, GLUT_DOUBLE, GLUT_DEPTH,
  148.   GLUT_ACCUM, GLUT_ALPHA, GLUT_STENCIL, GLUT_MULTISAMPLE, GLUT_STEREO};
  149. int modes[MODES] =
  150. {0};
  151. Boolean menuButton[3] =
  152. {0, 0, 1};
  153. enum {
  154.   MOUSEBUTTON, MOUSEMOTION, APPLY, RESET
  155. };
  156.  
  157. /* Prototypes */
  158.  
  159. void gfxInit(int);
  160. void drawScene(void);
  161. void idleFunc(void);
  162. void reshapeFunc(int width, int height);
  163. void visible(int state);
  164. void keyFunc(unsigned char key, int x, int y);
  165. void mouseFunc(int button, int state, int x, int y);
  166. void motionFunc(int x, int y);
  167. void passiveMotionFunc(int x, int y);
  168. void entryFunc(int state);
  169. void specialFunc(int key, int x, int y);
  170. void menuStateFunc(int state);
  171. void timerFunc(int value);
  172. #if 0
  173. void delayedReinstateMenuStateCallback(int value);
  174. #endif
  175. void menuFunc(int value);
  176. void showText(void);
  177. void textString(int x, int y, char *str, void *font);
  178. void strokeString(int x, int y, char *str, void *font);
  179. void makeMenus(void);
  180. int idToIndex(int id);
  181. void setInitDisplayMode(void);
  182. void createMenu6(void);
  183. void removeCallbacks(void);
  184. void addCallbacks(void);
  185. void dumpIds(void);
  186. void updateHelp(void);
  187. void updateAll(void);
  188. void killWindow(int index);
  189. void makeWindow(int index);
  190. void warning(char *msg);
  191. void autoDemo(int);
  192. void positionWindow(int index);
  193. void reshapeWindow(int index);
  194. void iconifyWindow(int index);
  195. void showWindow(int index);
  196. void hideWindow(int index);
  197. void pushWindow(int index);
  198. void popWindow(int index);
  199. void attachMenus(void);
  200. void killAllWindows(void);
  201. void makeAllWindows(void);
  202. void updateText(void);
  203. void updateScrollWindow(int index, char **ptr);
  204. void redefineShapes(int shape);
  205. Boolean match(char *, char *);
  206. void checkArgs(int argc, char *argv[]);
  207. void scaleWindows(float);
  208. void commandLineHelp(void);
  209. void trackBall(int mode, int button, int state, int x, int y);
  210.  
  211. void spaceballMotionCB(int, int, int);
  212. void spaceballRotateCB(int, int, int);
  213. void spaceballButtonCB(int, int);
  214. void buttonBoxCB(int, int);
  215. void dialsCB(int, int);
  216. void tabletMotionCB(int, int);
  217. void tabletButtonCB(int, int, int, int);
  218.  
  219. /* main */
  220.  
  221. int
  222. main(int argc, char **argv)
  223. {
  224.  
  225. /* General init */
  226.  
  227.   glutInit(&argc, argv);
  228.  
  229. /* Check args */
  230.  
  231.   checkArgs(argc, argv);
  232.  
  233. /* Scale window position/size if needed. Ignore aspect ratios. */
  234.  
  235.   if (scaleFactor > 0.0)
  236.     scaleWindows(scaleFactor);
  237.   else
  238.     scaleWindows(glutGet(GLUT_SCREEN_WIDTH) / 1280.0);
  239.  
  240. /* Set initial display mode */
  241.  
  242.   modes[RGBA] = 1;
  243.   modes[DOUBLE] = 1;
  244.   modes[DEPTH] = 1;
  245.   setInitDisplayMode();
  246.  
  247. /* Set up menus */
  248.  
  249.   makeMenus();
  250.  
  251. /* Make some windows */
  252.  
  253.   makeWindow(0);
  254.   makeWindow(1);
  255.  
  256. /* Global callbacks */
  257.  
  258.   glutIdleFunc(idleFunc);
  259.   glutMenuStateFunc(menuStateFunc);
  260.  
  261. /* Start demo if needed */
  262.  
  263.   if (demoMode)
  264.     autoDemo(-2);
  265.  
  266. /* Fall into event loop */
  267.  
  268.   glutMainLoop();
  269.   return 0;             /* ANSI C requires main to return int. */
  270. }
  271.  
  272. /* gfxInit - Init opengl for each window */
  273.  
  274. void
  275. gfxInit(int index)
  276. {
  277.   GLfloat grey10[] =
  278.   {0.10, 0.10, 0.10, 1.0};
  279.   GLfloat grey20[] =
  280.   {0.2, 0.2, 0.2, 1.0};
  281.   GLfloat black[] =
  282.   {0.0, 0.0, 0.0, 0.0};
  283.   GLfloat diffuse0[] =
  284.   {1.0, 0.0, 0.0, 1.0};
  285.   GLfloat diffuse1[] =
  286.   {0.0, 1.0, 0.0, 1.0};
  287.   GLfloat diffuse2[] =
  288.   {1.0, 1.0, 0.0, 1.0};
  289.   GLfloat diffuse3[] =
  290.   {0.0, 1.0, 1.0, 1.0};
  291.   GLfloat diffuse4[] =
  292.   {1.0, 0.0, 1.0, 1.0};
  293.  
  294. #define XX  3
  295. #define YY  3
  296. #define ZZ  -2.5
  297.  
  298.   float vertex[][3] =
  299.   {
  300.     {-XX, -YY, ZZ},
  301.     {+XX, -YY, ZZ},
  302.     {+XX, +YY, ZZ},
  303.     {-XX, +YY, ZZ}
  304.   };
  305.  
  306. /* warning: This func mixes RGBA and CMAP calls in an ugly
  307.    fashion */
  308.  
  309.   redefineShapes(currentShape);  /* set up display lists  */
  310.   glutSetWindow(winId[index]);  /* hack - redefineShapes
  311.                                    changes glut win */
  312.  
  313. /* Shaded backdrop square (RGB or CMAP) */
  314.  
  315.   glNewList(100, GL_COMPILE);
  316.   glPushAttrib(GL_LIGHTING);
  317.   glDisable(GL_LIGHTING);
  318.   glBegin(GL_POLYGON);
  319.  
  320.   glColor4fv(black);
  321.   glIndexi(0);
  322.   glVertex3fv(vertex[0]);
  323.  
  324.   glColor4fv(grey10);
  325.   glIndexi(3);
  326.   glVertex3fv(vertex[1]);
  327.  
  328.   glColor4fv(grey20);
  329.   glIndexi(4);
  330.   glVertex3fv(vertex[2]);
  331.  
  332.   glColor4fv(grey10);
  333.   glIndexi(7);
  334.   glVertex3fv(vertex[3]);
  335.  
  336.   glEnd();
  337.   glPopAttrib();
  338.   glIndexi(9);
  339.   glEndList();
  340.  
  341. /* Set proj+view */
  342.  
  343.   glMatrixMode(GL_PROJECTION);
  344.   glLoadIdentity();
  345.   gluPerspective(40.0, 1.0, 1.0, 20.0);
  346.   glMatrixMode(GL_MODELVIEW);
  347.   glLoadIdentity();
  348.   gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.);
  349.   glTranslatef(0.0, 0.0, -1.0);
  350.  
  351.   if (index == 6 || index == 7)
  352.     goto colorindex;
  353.  
  354. /* Set basic material, lighting for RGB windows */
  355.  
  356.   if (index == 0)
  357.     glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse0);
  358.   else if (index == 1)
  359.     glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse1);
  360.   else if (index == 2)
  361.     glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse2);
  362.   else if (index == 3)
  363.     glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse3);
  364.   else if (index == 4)
  365.     glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse4);
  366.  
  367.   glEnable(GL_LIGHTING);
  368.   glEnable(GL_LIGHT0);
  369.   glEnable(GL_DEPTH_TEST);
  370.  
  371.   if (index == 4)
  372.     glClearColor(0.15, 0.15, 0.15, 1);
  373.   else
  374.     glClearColor(0.1, 0.1, 0.1, 1.0);
  375.  
  376.   return;
  377.  
  378. /* Set GL basics for CMAP windows 6,7 */
  379.  
  380. colorindex:
  381.  
  382.   glEnable(GL_DEPTH_TEST);
  383.   if (glutGet(GLUT_WINDOW_COLORMAP_SIZE) < 16)
  384.     warning("Color map size too small for color index window");
  385.  
  386. /* Try to reuse an existing color map */
  387.  
  388.   if ((index == 6) && (winId[7] != 0)) {
  389.     glutCopyColormap(winId[7]);
  390.   } else if ((index == 7) && (winId[6] != 0)) {
  391.     glutCopyColormap(winId[6]);
  392.   } else {
  393.     glutSetColor(8, 0.1, 0.1, 0.1);
  394.     glutSetColor(9, 1.0, 0.5, 0.0);
  395.     glutSetColor(10, 1.0, 0.6, 0.8);
  396.   }
  397.   glClearIndex(8);
  398.   glIndexi(index + 3);
  399.  
  400. }
  401.  
  402. /* makeMenus - Create popup menus */
  403.  
  404. void
  405. makeMenus(void)
  406. {
  407.  
  408. /* General control / debug */
  409.  
  410.   menu2 = glutCreateMenu(menuFunc);
  411.   glutAddMenuEntry("toggle auto demo mode (a)", 312);
  412.   glutAddMenuEntry("toggle freezing in menus", 300);
  413.   glutAddMenuEntry("toggle text per window (t)", 301);
  414.   glutAddMenuEntry("toggle global timer", 302);
  415.   glutAddMenuEntry("toggle global animation", 303);
  416.   glutAddMenuEntry("toggle per window animation", 304);
  417.   glutAddMenuEntry("toggle debug prints (D)", 305);
  418.   glutAddMenuEntry("toggle shaded backdrop", 307);
  419.   glutAddMenuEntry("toggle passive motion callback", 308);
  420.   glutAddMenuEntry("increase line width (l)", 310);
  421.   glutAddMenuEntry("decrease line width  (L)", 311);
  422.  
  423. /* Shapes */
  424.  
  425.   menu3 = glutCreateMenu(menuFunc);
  426.   glutAddMenuEntry("sphere", 200);
  427.   glutAddMenuEntry("cube", 201);
  428.   glutAddMenuEntry("cone", 202);
  429.   glutAddMenuEntry("torus", 203);
  430.   glutAddMenuEntry("dodecahedron", 204);
  431.   glutAddMenuEntry("octahedron", 205);
  432.   glutAddMenuEntry("tetrahedron", 206);
  433.   glutAddMenuEntry("icosahedron", 207);
  434.   glutAddMenuEntry("teapot", 208);
  435.  
  436. /* Open/close windows */
  437.  
  438.   menu4 = glutCreateMenu(menuFunc);
  439.   glutAddMenuEntry("open all windows", 450);
  440.   glutAddMenuEntry("close all windows", 451);
  441.   glutAddMenuEntry(" ", 9999);
  442.   glutAddMenuEntry("create win 0", 400);
  443.   glutAddMenuEntry("create win 1", 401);
  444.   glutAddMenuEntry("create win 2", 402);
  445.   glutAddMenuEntry("create win 3", 403);
  446.   glutAddMenuEntry("create sub window", 404);
  447.   glutAddMenuEntry("create color index win 6", 406);
  448.   glutAddMenuEntry("create color index win 7", 407);
  449.   glutAddMenuEntry(" ", 9999);
  450.   glutAddMenuEntry("destroy win 0", 410);
  451.   glutAddMenuEntry("destroy win 1", 411);
  452.   glutAddMenuEntry("destroy win 2", 412);
  453.   glutAddMenuEntry("destroy win 3", 413);
  454.   glutAddMenuEntry("destroy sub window", 414);
  455.   glutAddMenuEntry("destroy color index win 6", 416);
  456.   glutAddMenuEntry("destroy color index win 7", 417);
  457.  
  458. /* Window manager stuff */
  459.  
  460.   menu5 = glutCreateMenu(menuFunc);
  461.   glutAddMenuEntry("move current win", 430);
  462.   glutAddMenuEntry("resize current win", 431);
  463.   glutAddMenuEntry("iconify current win", 432);
  464.   glutAddMenuEntry("show current win", 433);
  465.   glutAddMenuEntry("hide current win", 434);
  466.   glutAddMenuEntry("push current win", 435);
  467.   glutAddMenuEntry("pop current win", 436);
  468.   glutAddMenuEntry(" ", 9999);
  469.   glutAddMenuEntry("move win 1", 420);
  470.   glutAddMenuEntry("resize win 1", 421);
  471.   glutAddMenuEntry("iconify win 1", 422);
  472.   glutAddMenuEntry("show win 1", 423);
  473.   glutAddMenuEntry("hide win 1", 424);
  474.   glutAddMenuEntry("push win 1", 425);
  475.   glutAddMenuEntry("pop win 1", 426);
  476.  
  477. /* Gfx modes */
  478.  
  479.   createMenu6();        /* build dynamically  */
  480.  
  481. /* Texty reports */
  482.  
  483.   menu7 = glutCreateMenu(menuFunc);
  484.   glutAddMenuEntry("report current win modes", 700);
  485.   glutAddMenuEntry("report current device data", 701);
  486.   glutAddMenuEntry("check OpenGL extensions", 702);
  487.   glutAddMenuEntry("dump internal data (d)", 703);
  488.  
  489. /* Play with menus */
  490.  
  491.   menu8 = glutCreateMenu(menuFunc);
  492.   glutAddMenuEntry("toggle menus on left button", 805);
  493.   glutAddMenuEntry("toggle menus on middle button", 806);
  494.   glutAddMenuEntry("toggle menus on right button", 807);
  495.   glutAddMenuEntry("---------------------------", 9999);
  496.   glutAddMenuEntry("add plain items", 800);
  497.   glutAddMenuEntry("add submenu items", 801);
  498.   glutAddMenuEntry("change new entries to plain items", 802);
  499.   glutAddMenuEntry("change new entries to submenus", 803);
  500.   glutAddMenuEntry("remove all new items", 804);
  501.   glutAddMenuEntry("---------------------------", 9999);
  502.  
  503. /* Main menu */
  504.  
  505.   menu1 = glutCreateMenu(menuFunc);
  506.   glutAddSubMenu("control", menu2);
  507.   glutAddSubMenu("shapes", menu3);
  508.   glutAddSubMenu("windows", menu4);
  509.   glutAddSubMenu("window ops", menu5);
  510.   glutAddSubMenu("gfx modes", menu6);
  511.   glutAddSubMenu("reports", menu7);
  512.   glutAddSubMenu("menus", menu8);
  513.   glutAddMenuEntry("help (h)", 101);
  514.   glutAddMenuEntry("quit (esc)", 100);
  515. }
  516.  
  517. /* createMenu6 - Dynamically rebuild menu of display modes to
  518.    show current choices */
  519.  
  520. void
  521. createMenu6(void)
  522. {
  523.   char str[100];
  524.   int i;
  525.  
  526.   if (menu6 != 0)
  527.     glutDestroyMenu(menu6);
  528.   menu6 = glutCreateMenu(menuFunc);
  529.  
  530.   for (i = 0; i < MODES; i++) {
  531.     sprintf(str, "%srequest %s", (modes[i] ? "+ " : "   "), modeNames[i]);
  532.     glutAddMenuEntry(str, 602 + i);
  533.   }
  534. }
  535.  
  536. /* menuFunc - Process return codes from popup menus */
  537.  
  538. void
  539. menuFunc(int value)
  540. {
  541.   static int initItems = 10;
  542.   int items, m;
  543.  
  544.   if (initItems == 0) {
  545.     glutSetMenu(menu8);
  546.     initItems = glutGet(GLUT_MENU_NUM_ITEMS);
  547.   }
  548.   PR("Menu returned value %d \n", value);
  549.  
  550.   switch (value) {
  551.  
  552. /* GLUT shapes */
  553.  
  554.   case 200:
  555.   case 201:
  556.   case 202:
  557.   case 203:
  558.   case 204:
  559.   case 205:
  560.   case 206:
  561.   case 207:
  562.   case 208:
  563.     redefineShapes(value - 200);
  564.     break;
  565.  
  566. /* Overall controls */
  567.  
  568.   case 300:
  569.     menuFreeze = !menuFreeze;
  570.     break;
  571.  
  572.   case 301:
  573.     text[idToIndex(glutGetWindow())] = !(text[idToIndex(glutGetWindow())]);
  574.     break;
  575.  
  576.   case 302:
  577.     timerOn = !timerOn;
  578.     if (timerOn)
  579.       glutTimerFunc(DELAY, timerFunc, 1);
  580.     break;
  581.  
  582.   case 303:
  583.     animation = !animation;
  584.     if (animation)
  585.       glutIdleFunc(idleFunc);
  586.     else
  587.       glutIdleFunc(NULL);
  588.     break;
  589.  
  590.   case 304:
  591.     winFreeze[idToIndex(glutGetWindow())] = !(winFreeze[idToIndex(
  592.           glutGetWindow())]);
  593.     break;
  594.  
  595.   case 305:
  596.     debug = !debug;
  597.     break;
  598.  
  599.   case 307:
  600.     backdrop = !backdrop;
  601.     break;
  602.  
  603.   case 308:
  604.     passive = !passive;
  605.     if (passive)
  606.       glutPassiveMotionFunc(passiveMotionFunc);
  607.     else
  608.       glutPassiveMotionFunc(NULL);
  609.     break;
  610.  
  611.   case 310:
  612.     lineWidth += 1;
  613.     updateAll();
  614.     break;
  615.  
  616.   case 311:
  617.     lineWidth -= 1;
  618.     if (lineWidth < 1)
  619.       lineWidth = 1;
  620.     updateAll();
  621.     break;
  622.  
  623.   case 312:
  624.     demoMode = !demoMode;
  625.     if (demoMode)
  626.       autoDemo(-2);
  627.     break;
  628.  
  629. /* Window create/destroy. */
  630.  
  631. /* Creates */
  632.  
  633.   case 400:
  634.     makeWindow(0);
  635.     break;
  636.  
  637.   case 401:
  638.     makeWindow(1);
  639.     break;
  640.  
  641.   case 402:
  642.     makeWindow(2);
  643.     break;
  644.  
  645.   case 403:
  646.     makeWindow(3);
  647.     break;
  648.  
  649.   case 404:
  650.     makeWindow(4);
  651.     break;
  652.  
  653.   case 406:
  654.     makeWindow(6);
  655.     break;
  656.  
  657.   case 407:
  658.     makeWindow(7);
  659.     break;
  660.  
  661. /* Destroys */
  662.  
  663.   case 410:
  664.     killWindow(0);
  665.     break;
  666.  
  667.   case 411:
  668.     killWindow(1);
  669.     break;
  670.  
  671.   case 412:
  672.     killWindow(2);
  673.     break;
  674.  
  675.   case 413:
  676.     killWindow(3);
  677.     break;
  678.  
  679.   case 414:
  680.     killWindow(4);
  681.     break;
  682.  
  683.   case 416:
  684.     killWindow(6);
  685.     break;
  686.  
  687.   case 417:
  688.     killWindow(7);
  689.     break;
  690.  
  691.   case 450:
  692.     makeAllWindows();
  693.     break;
  694.  
  695.   case 451:
  696.     killAllWindows();
  697.     break;
  698.  
  699. /* Window movements etc. */
  700.  
  701.   case 420:
  702.     positionWindow(1);
  703.     break;
  704.  
  705.   case 421:
  706.     reshapeWindow(1);
  707.     break;
  708.  
  709.   case 422:
  710.     iconifyWindow(1);
  711.     break;
  712.  
  713.   case 423:
  714.     showWindow(1);
  715.     break;
  716.  
  717.   case 424:
  718.     hideWindow(1);
  719.     break;
  720.  
  721.   case 425:
  722.     pushWindow(1);
  723.     break;
  724.  
  725.   case 426:
  726.     popWindow(1);
  727.     break;
  728.  
  729.   case 430:
  730.     positionWindow(idToIndex(glutGetWindow()));
  731.     break;
  732.  
  733.   case 431:
  734.     reshapeWindow(idToIndex(glutGetWindow()));
  735.     break;
  736.  
  737.   case 432:
  738.     iconifyWindow(idToIndex(glutGetWindow()));
  739.     break;
  740.  
  741.   case 433:
  742.     showWindow(idToIndex(glutGetWindow()));
  743.     break;
  744.  
  745.   case 434:
  746.     hideWindow(idToIndex(glutGetWindow()));
  747.     break;
  748.  
  749.   case 435:
  750.     pushWindow(idToIndex(glutGetWindow()));
  751.     break;
  752.  
  753.   case 436:
  754.     popWindow(idToIndex(glutGetWindow()));
  755.     break;
  756.  
  757. /* Test gfx modes. */
  758.  
  759.   case 600:
  760.     makeWindow(3);
  761.     break;
  762.  
  763.   case 601:
  764.     killWindow(3);
  765.     break;
  766.  
  767.   case 602:
  768.   case 603:
  769.   case 604:
  770.   case 605:
  771.   case 606:
  772.   case 607:
  773.   case 608:
  774.   case 609:
  775.   case 610:
  776.   case 611:
  777.     modes[value - 602] = !modes[value - 602];
  778.     setInitDisplayMode();
  779.     break;
  780.  
  781. /* Text reports */
  782.  
  783. /* This is pretty ugly. */
  784.  
  785. #define INDENT 30
  786. #define REPORTSTART(text)                          \
  787.         printf("\n" text "\n");                    \
  788.         textPtr[0] = (char *)malloc(strlen(text)+1); \
  789.     strcpy(textPtr[0], text);                  \
  790.         textCount = 1;
  791.  
  792. #define REPORTEND                                  \
  793.         scrollLine = 0;                            \
  794.         textPtr[textCount] = NULL;                 \
  795.         makeWindow(8);                             \
  796.         updateText();
  797.  
  798. #define GLUTGET(name)                              \
  799.        {                                           \
  800.           char str[100], str2[100];                \
  801.           int s, len;                              \
  802.           sprintf(str, # name);                    \
  803.           len = strlen(# name);                    \
  804.           for(s = 0 ; s < INDENT-len; s++)         \
  805.             strcat(str, " ");                      \
  806.           sprintf(str2, ": %d\n",glutGet(name));   \
  807.       strcat(str, str2);                       \
  808.       printf(str);                             \
  809.       textPtr[textCount] =                     \
  810.             (char *)malloc(strlen(str)+1);       \
  811.       strcpy(textPtr[textCount], str);         \
  812.        textCount++;                             \
  813.        }
  814.  
  815.   case 700:
  816.  
  817.     printf("XXXXXX glutGetWindow = %d\n", glutGetWindow());
  818.     REPORTSTART("glutGet():");
  819.  
  820.     GLUTGET(GLUT_WINDOW_X);
  821.     GLUTGET(GLUT_WINDOW_Y);
  822.     GLUTGET(GLUT_WINDOW_WIDTH);
  823.     GLUTGET(GLUT_WINDOW_HEIGHT);
  824.     GLUTGET(GLUT_WINDOW_BUFFER_SIZE);
  825.     GLUTGET(GLUT_WINDOW_STENCIL_SIZE);
  826.     GLUTGET(GLUT_WINDOW_DEPTH_SIZE);
  827.     GLUTGET(GLUT_WINDOW_RED_SIZE);
  828.     GLUTGET(GLUT_WINDOW_GREEN_SIZE);
  829.     GLUTGET(GLUT_WINDOW_BLUE_SIZE);
  830.     GLUTGET(GLUT_WINDOW_ALPHA_SIZE);
  831.     GLUTGET(GLUT_WINDOW_ACCUM_RED_SIZE);
  832.     GLUTGET(GLUT_WINDOW_ACCUM_GREEN_SIZE);
  833.     GLUTGET(GLUT_WINDOW_ACCUM_BLUE_SIZE);
  834.     GLUTGET(GLUT_WINDOW_ACCUM_ALPHA_SIZE);
  835.     GLUTGET(GLUT_WINDOW_DOUBLEBUFFER);
  836.     GLUTGET(GLUT_WINDOW_RGBA);
  837.     GLUTGET(GLUT_WINDOW_PARENT);
  838.     GLUTGET(GLUT_WINDOW_NUM_CHILDREN);
  839.     GLUTGET(GLUT_WINDOW_COLORMAP_SIZE);
  840.     GLUTGET(GLUT_WINDOW_NUM_SAMPLES);
  841.     GLUTGET(GLUT_STEREO);
  842.     GLUTGET(GLUT_SCREEN_WIDTH);
  843.     GLUTGET(GLUT_SCREEN_HEIGHT);
  844.     GLUTGET(GLUT_SCREEN_HEIGHT_MM);
  845.     GLUTGET(GLUT_SCREEN_WIDTH_MM);
  846.     GLUTGET(GLUT_MENU_NUM_ITEMS);
  847.     GLUTGET(GLUT_DISPLAY_MODE_POSSIBLE);
  848.     GLUTGET(GLUT_INIT_DISPLAY_MODE);
  849.     GLUTGET(GLUT_INIT_WINDOW_X);
  850.     GLUTGET(GLUT_INIT_WINDOW_Y);
  851.     GLUTGET(GLUT_INIT_WINDOW_WIDTH);
  852.     GLUTGET(GLUT_INIT_WINDOW_HEIGHT);
  853.     GLUTGET(GLUT_ELAPSED_TIME);
  854.  
  855.     REPORTEND;
  856.     break;
  857.  
  858. #define GLUTDEVGET(name)                         \
  859.         {                                        \
  860.           char str[100], str2[100];              \
  861.           int len, s;                            \
  862.           sprintf(str, # name);                  \
  863.           len = strlen(# name);                  \
  864.           for(s = 0 ; s < INDENT-len; s++)       \
  865.             strcat(str, " ");                    \
  866.           sprintf(str2, ": %d\n",                \
  867.          glutDeviceGet(name));               \
  868.       strcat(str, str2);                     \
  869.       printf(str);                           \
  870.       textPtr[textCount] =                   \
  871.           (char *)malloc(strlen(str)+1);       \
  872.       strcpy(textPtr[textCount], str);       \
  873.        textCount++;                           \
  874.     }
  875.  
  876.   case 701:
  877.     REPORTSTART("glutDeviceGet():");
  878.  
  879.     GLUTDEVGET(GLUT_HAS_KEYBOARD);
  880.     GLUTDEVGET(GLUT_HAS_MOUSE);
  881.     GLUTDEVGET(GLUT_HAS_SPACEBALL);
  882.     GLUTDEVGET(GLUT_HAS_DIAL_AND_BUTTON_BOX);
  883.     GLUTDEVGET(GLUT_HAS_TABLET);
  884.     GLUTDEVGET(GLUT_NUM_MOUSE_BUTTONS);
  885.     GLUTDEVGET(GLUT_NUM_SPACEBALL_BUTTONS);
  886.     GLUTDEVGET(GLUT_NUM_BUTTON_BOX_BUTTONS);
  887.     GLUTDEVGET(GLUT_NUM_DIALS);
  888.     GLUTDEVGET(GLUT_NUM_TABLET_BUTTONS);
  889.  
  890.     REPORTEND;
  891.     break;
  892.  
  893. #define EXTCHECK(name)                           \
  894.         {                                        \
  895.           char str[100], str2[100];              \
  896.           int len, s;                            \
  897.           sprintf(str, # name);                  \
  898.           len = strlen(# name);                  \
  899.           for(s = 0 ; s < INDENT-len; s++)       \
  900.             strcat(str, " ");                    \
  901.           sprintf(str2, ": %s\n",                \
  902.          glutExtensionSupported(# name)?     \
  903.            "yes": "no");                     \
  904.       strcat(str, str2);                     \
  905.       printf(str);                           \
  906.       textPtr[textCount] =                   \
  907.          (char *)malloc(strlen(str)+1);        \
  908.       strcpy(textPtr[textCount], str);       \
  909.        textCount++;                           \
  910.         }
  911.  
  912.   case 702:
  913.     REPORTSTART("glutExtensionSupported():");
  914.  
  915.     EXTCHECK(GL_EXT_abgr);
  916.     EXTCHECK(GL_EXT_blend_color);
  917.     EXTCHECK(GL_EXT_blend_minmax);
  918.     EXTCHECK(GL_EXT_blend_logic_op);
  919.     EXTCHECK(GL_EXT_blend_subtract);
  920.     EXTCHECK(GL_EXT_polygon_offset);
  921.     EXTCHECK(GL_EXT_texture);
  922.     EXTCHECK(GL_EXT_guaranteed_to_fail);
  923.     EXTCHECK(GLX_SGI_swap_control);
  924.     EXTCHECK(GLX_SGI_video_sync);
  925.     EXTCHECK(GLX_SGIS_multi_sample);
  926.  
  927.     REPORTEND;
  928.     break;
  929.  
  930.   case 703:
  931.     dumpIds();
  932.     break;
  933.  
  934. /* Mess around with menus */
  935.  
  936.   case 800:
  937.     if (glutGetMenu() != menu8)  /* just a test  */
  938.       printf("glutGetMenu() returned unexpected value\n");
  939.     glutAddMenuEntry("help", 101);
  940.     glutAddMenuEntry("help", 101);
  941.     glutAddMenuEntry("help", 101);
  942.     glutAddMenuEntry("help", 101);
  943.     glutAddMenuEntry("help", 101);
  944.     break;
  945.  
  946.   case 801:
  947.     glutAddSubMenu("shapes", menu3);
  948.     glutAddSubMenu("shapes", menu3);
  949.     glutAddSubMenu("shapes (a long string to break menus with)", menu3);
  950.     glutAddSubMenu("shapes", menu3);
  951.     glutAddSubMenu("shapes", menu3);
  952.     break;
  953.  
  954.   case 802:
  955.     items = glutGet(GLUT_MENU_NUM_ITEMS);
  956.     for (m = initItems + 1; m <= items; m++) {
  957.       glutChangeToMenuEntry(m, "help", 101);
  958.     }
  959.     break;
  960.  
  961.   case 803:
  962.     items = glutGet(GLUT_MENU_NUM_ITEMS);
  963.     for (m = initItems + 1; m <= items; m++) {
  964.       glutChangeToSubMenu(m, "shapes", menu3);
  965.     }
  966.     break;
  967.  
  968.   case 804:
  969.     items = glutGet(GLUT_MENU_NUM_ITEMS);
  970.     /* reverse order so renumbering not aproblem  */
  971.     for (m = items; m >= initItems + 1; m--) {
  972.       glutRemoveMenuItem(m);
  973.     }
  974.     break;
  975.  
  976.   case 805:
  977.     menuButton[0] = !menuButton[0];
  978.     attachMenus();
  979.     break;
  980.  
  981.   case 806:
  982.     menuButton[1] = !menuButton[1];
  983.     attachMenus();
  984.     break;
  985.  
  986.   case 807:
  987.     menuButton[2] = !menuButton[2];
  988.     attachMenus();
  989.     break;
  990.  
  991. /* Direct menu items.  */
  992.  
  993.   case 100:
  994.     exit(0);
  995.     break;
  996.  
  997.   case 101:
  998.     if (winId[5] == 0)
  999.       makeWindow(5);
  1000.     else
  1001.       killWindow(5);
  1002.     break;
  1003.  
  1004.   case 9999:
  1005.     break;
  1006.  
  1007.   default:
  1008.     fprintf(stderr, "\007Unhandled case %d in menu callback\n", value);
  1009.   }
  1010.  
  1011. }
  1012.  
  1013. /* redefineShapes - Remake the shapes display lists */
  1014.  
  1015. void
  1016. redefineShapes(int shape)
  1017. {
  1018.   int i;
  1019.  
  1020. #define C3                \
  1021.         switch(i)        \
  1022.      {                \
  1023.          case 0:      \
  1024.          case 3:      \
  1025.            C1;        \
  1026.            break;     \
  1027.                       \
  1028.          case 1:      \
  1029.          case 2:      \
  1030.          case 4:      \
  1031.          case 6:      \
  1032.          case 7:      \
  1033.            C2;        \
  1034.            break;     \
  1035.      }                \
  1036.      currentShape = shape
  1037.  
  1038.   for (i = 0; i < MAXWIN; i++) {
  1039.     if (winId[i]) {
  1040.       glutSetWindow(winId[i]);
  1041.       if (glIsList(i + 1))
  1042.         glDeleteLists(i + 1, 1);
  1043.       glNewList(i + 1, GL_COMPILE);
  1044.  
  1045.       switch (shape) {
  1046.  
  1047. #undef  C1
  1048. #define C1  glutSolidSphere(1.5, 10, 10)
  1049. #undef  C2
  1050. #define C2  glutWireSphere(1.5, 10, 10)
  1051.  
  1052.       case 0:
  1053.         C3;
  1054.         break;
  1055.  
  1056. #undef  C1
  1057. #define C1 glutSolidCube(2)
  1058. #undef  C2
  1059. #define C2 glutWireCube(2)
  1060.  
  1061.       case 1:
  1062.         C3;
  1063.         break;
  1064.  
  1065. #undef  C1
  1066. #define C1 glutSolidCone(1.5, 1.75, 10, 10);
  1067. #undef  C2
  1068. #define C2 glutWireCone(1.5, 1.75, 10, 10);
  1069.  
  1070.       case 2:
  1071.         C3;
  1072.         break;
  1073.  
  1074. #undef  C1
  1075. #define C1 glutSolidTorus(0.5, 1.1, 10, 10)
  1076. #undef  C2
  1077. #define C2 glutWireTorus(0.5, 1.1, 10, 10)
  1078.  
  1079.       case 3:
  1080.         C3;
  1081.         break;
  1082.  
  1083. #undef  C1
  1084. #define C1 glScalef(.8, .8, .8);glutSolidDodecahedron()
  1085. #undef  C2
  1086. #define C2 glScalef(.8, .8, .8);glutWireDodecahedron()
  1087.  
  1088.       case 4:
  1089.         C3;
  1090.         break;
  1091.  
  1092. #undef  C1
  1093. #define C1 glScalef(1.5, 1.5, 1.5);glutSolidOctahedron()
  1094. #undef  C2
  1095. #define C2 glScalef(1.5, 1.5, 1.5);glutWireOctahedron()
  1096.  
  1097.       case 5:
  1098.         C3;
  1099.         break;
  1100.  
  1101. #undef  C1
  1102. #define C1 glScalef(1.8, 1.8, 1.8);glutSolidTetrahedron()
  1103. #undef  C2
  1104. #define C2 glScalef(1.8, 1.8, 1.8);glutWireTetrahedron()
  1105.  
  1106.       case 6:
  1107.         C3;
  1108.         break;
  1109.  
  1110. #undef  C1
  1111. #define C1 glScalef(1.5, 1.5, 1.5);glutSolidIcosahedron()
  1112. #undef  C2
  1113. #define C2 glScalef(1.5, 1.5, 1.5);glutWireIcosahedron()
  1114.  
  1115.       case 7:
  1116.         C3;
  1117.         break;
  1118.  
  1119. #undef  C1
  1120. #define C1 glutSolidTeapot(1.5);
  1121. #undef  C2
  1122. #define C2 glutWireTeapot(1.5);
  1123.  
  1124.       case 8:
  1125.         C3;
  1126.         break;
  1127.       }
  1128.       glEndList();
  1129.     }
  1130.   }
  1131. }
  1132.  
  1133. /* positionWindow - Shift a window */
  1134.  
  1135. void
  1136. positionWindow(int index)
  1137. {
  1138.   int x, y;
  1139.  
  1140.   if (winId[index] == 0)
  1141.     return;
  1142.  
  1143.   glutSetWindow(winId[index]);
  1144.   x = glutGet(GLUT_WINDOW_X);
  1145.   y = glutGet(GLUT_WINDOW_Y);
  1146.   glutPositionWindow(x + 50, y + 50);
  1147. }
  1148.  
  1149. /* reshapeWindow - Change window size a little */
  1150.  
  1151. void
  1152. reshapeWindow(int index)
  1153. {
  1154.   int x, y;
  1155.  
  1156.   if (winId[index] == 0)
  1157.     return;
  1158.   glutSetWindow(winId[index]);
  1159.   x = glutGet(GLUT_WINDOW_WIDTH);
  1160.   y = glutGet(GLUT_WINDOW_HEIGHT);
  1161. /* glutReshapeWindow(x * (index % 2? 0.8: 1.2), y * (index % 2? 
  1162.  
  1163.    1.2: 0.8)); */
  1164.   glutReshapeWindow(x * 1.0, y * 0.8);
  1165. }
  1166.  
  1167. /* iconifyWindow - Iconify a window */
  1168.  
  1169. void
  1170. iconifyWindow(int index)
  1171. {
  1172.   if (winId[index] == 0)
  1173.     return;
  1174.   glutSetWindow(winId[index]);
  1175.   glutIconifyWindow();
  1176. }
  1177.  
  1178. /* showWindow - Show a window (map or uniconify it) */
  1179.  
  1180. void
  1181. showWindow(int index)
  1182. {
  1183.   if (winId[index] == 0)
  1184.     return;
  1185.   glutSetWindow(winId[index]);
  1186.   glutShowWindow();
  1187. }
  1188.  
  1189. /* hideWindow - Hide a window (unmap it) */
  1190.  
  1191. void
  1192. hideWindow(int index)
  1193. {
  1194.   if (winId[index] == 0)
  1195.     return;
  1196.   glutSetWindow(winId[index]);
  1197.   glutHideWindow();
  1198. }
  1199.  
  1200. /* pushWindow - Push a window */
  1201.  
  1202. void
  1203. pushWindow(int index)
  1204. {
  1205.   if (winId[index] == 0)
  1206.     return;
  1207.   glutSetWindow(winId[index]);
  1208.   glutPushWindow();
  1209. }
  1210.  
  1211. /* popWindow - Pop a window */
  1212.  
  1213. void
  1214. popWindow(int index)
  1215. {
  1216.   if (winId[index] == 0)
  1217.     return;
  1218.   glutSetWindow(winId[index]);
  1219.   glutPopWindow();
  1220. }
  1221.  
  1222. /* drawScene - Draw callback, triggered by expose events etc.
  1223.    in GLUT. */
  1224.  
  1225. void
  1226. drawScene(void)
  1227. {
  1228.   int winIndex;
  1229.  
  1230.   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  1231.  
  1232.   winIndex = idToIndex(glutGetWindow());
  1233.   /* printf("drawScene for index %d, id %d\n", winIndex,
  1234.      glutGetWindow());  */
  1235.  
  1236.   glPushMatrix();
  1237.   glLineWidth(lineWidth);
  1238.   if (backdrop)
  1239.     glCallList(100);
  1240.  
  1241.   /* Left button spinning  */
  1242.  
  1243.   trackBall(APPLY, 0, 0, 0, 0);
  1244.  
  1245.   /* Apply continuous spinning  */
  1246.  
  1247.   glRotatef(angle, 0, 1, 0);
  1248.  
  1249.   glCallList(winIndex + 1);
  1250.   glPopMatrix();
  1251.  
  1252.   if (text[winIndex])
  1253.     showText();
  1254.  
  1255.   glutSwapBuffers();
  1256. }
  1257.  
  1258. /* showText - Render some text in the current GLUT window */
  1259.  
  1260. void
  1261. showText(void)
  1262. {
  1263.   glMatrixMode(GL_PROJECTION);
  1264.   glPushMatrix();
  1265.   glLoadIdentity();
  1266.   gluOrtho2D(0, 100, 0, 100);
  1267.   glMatrixMode(GL_MODELVIEW);
  1268.   glPushMatrix();
  1269.   glLoadIdentity();
  1270.  
  1271.   glColor3f(1.0, 1.0, 1.0);
  1272.   glIndexi(7);
  1273.  
  1274.   glDisable(GL_DEPTH_TEST);
  1275.   glDisable(GL_LIGHTING);
  1276.  
  1277.   glLineWidth(lineWidth);
  1278.  
  1279.   textString(1, 1, "GLUT_BITMAP_8_BY_13", GLUT_BITMAP_8_BY_13);
  1280.   textString(1, 5, "GLUT_BITMAP_9_BY_15", GLUT_BITMAP_9_BY_15);
  1281.   textString(1, 10, "GLUT_BITMAP_TIMES_ROMAN_10", GLUT_BITMAP_TIMES_ROMAN_10);
  1282.   textString(1, 15, "GLUT_BITMAP_TIMES_ROMAN_24", GLUT_BITMAP_TIMES_ROMAN_24);
  1283.  
  1284.   strokeString(1, 25, "GLUT_STROKE_ROMAN", GLUT_STROKE_ROMAN);
  1285.   strokeString(1, 35, "GLUT_STROKE_MONO_ROMAN", GLUT_STROKE_MONO_ROMAN);
  1286.  
  1287.   glEnable(GL_DEPTH_TEST);
  1288.   glEnable(GL_LIGHTING);
  1289.  
  1290.   glMatrixMode(GL_PROJECTION);
  1291.   glPopMatrix();
  1292.   glMatrixMode(GL_MODELVIEW);
  1293.   glPopMatrix();
  1294.  
  1295. }
  1296.  
  1297. /* textString - Bitmap font string */
  1298.  
  1299. void
  1300. textString(int x, int y, char *msg, void *font)
  1301. {
  1302.   glRasterPos2f(x, y);
  1303.   while (*msg) {
  1304.     glutBitmapCharacter(font, *msg);
  1305.     msg++;
  1306.   }
  1307. }
  1308.  
  1309. /* strokeString - Stroke font string */
  1310.  
  1311. void
  1312. strokeString(int x, int y, char *msg, void *font)
  1313. {
  1314.   glPushMatrix();
  1315.   glTranslatef(x, y, 0);
  1316.   glScalef(.04, .04, .04);
  1317.   while (*msg) {
  1318.     glutStrokeCharacter(font, *msg);
  1319.     msg++;
  1320.   }
  1321.   glPopMatrix();
  1322. }
  1323.  
  1324. /* idleFunc - GLUT idle func callback - animates windows */
  1325.  
  1326. void
  1327. idleFunc(void)
  1328. {
  1329.   int i;
  1330.  
  1331.   if (!leftDown && !middleDown)
  1332.     angle += 1;
  1333.  
  1334.   for (i = 0; i < MAXWIN; i++) {
  1335.     if (winId[i] && winVis[i] && !winFreeze[i]) {
  1336.       glutSetWindow(winId[i]);
  1337.       glutPostRedisplay();
  1338.     }
  1339.   }
  1340. }
  1341.  
  1342. /* reshapeFunc - Reshape callback. */
  1343.  
  1344. void
  1345. reshapeFunc(int width, int height)
  1346. {
  1347.   int winId;
  1348.   float aspect;
  1349.  
  1350.   winId = glutGetWindow();
  1351.   PR("reshape callback for window id %d \n", winId);
  1352.  
  1353.   glViewport(0, 0, width, height);
  1354.   aspect = (float) width / height;
  1355.  
  1356.   glMatrixMode(GL_PROJECTION);
  1357.   glLoadIdentity();
  1358.   gluPerspective(40.0, aspect, 1.0, 20.0);
  1359.   glMatrixMode(GL_MODELVIEW);
  1360. }
  1361.  
  1362. /* visible - Visibility callback. Turn off rendering in
  1363.    invisible windows */
  1364.  
  1365. void
  1366. visible(int state)
  1367. {
  1368.   int winId;
  1369.   static Boolean someVisible = TRUE;
  1370.  
  1371.   winId = glutGetWindow();
  1372.   /* printf("visible: state = %d \n", state);  */
  1373.  
  1374.   if (state == GLUT_VISIBLE) {
  1375.     PR("Window id %d visible \n", winId);
  1376.     winVis[idToIndex(winId)] = TRUE;
  1377.   } else {
  1378.     PR("Window %d not visible \n", winId);
  1379.     winVis[idToIndex(winId)] = FALSE;
  1380.   }
  1381.  
  1382.   if ((winVis[0] == FALSE) && (winVis[1] == FALSE) && (winVis[2] == FALSE)
  1383.     && (winVis[3] == FALSE) && (winVis[6] == FALSE) && (winVis[7] ==
  1384.       FALSE)) {
  1385.     glutIdleFunc(NULL);
  1386.     PR("All windows not visible; idle func disabled\n");
  1387.     someVisible = FALSE;
  1388.   } else {
  1389.     if (!someVisible) {
  1390.       PR("Some windows now visible; idle func enabled\n");
  1391.       someVisible = TRUE;
  1392.       if (animation)
  1393.         glutIdleFunc(idleFunc);
  1394.     }
  1395.   }
  1396. }
  1397.  
  1398. /* keyFunc - Ascii key callback */
  1399.  
  1400. void
  1401. keyFunc(unsigned char key, int x, int y)
  1402. {
  1403.   int i, ii;
  1404.  
  1405.   if (debug || showKeys)
  1406.     printf("Ascii key '%c' 0x%02x\n", key, key);
  1407.  
  1408.   switch (key) {
  1409.   case 0x1b:
  1410.     exit(0);
  1411.     break;
  1412.  
  1413.   case 'a':
  1414.     demoMode = !demoMode;
  1415.     if (demoMode)
  1416.       autoDemo(-2);
  1417.     break;
  1418.  
  1419.   case 's':
  1420.     AUTODELAY = AUTODELAY * 0.666;
  1421.     break;
  1422.  
  1423.   case 'S':
  1424.     AUTODELAY = AUTODELAY * 1.5;
  1425.     break;
  1426.  
  1427.   case 'q':
  1428.     killWindow(idToIndex(glutGetWindow()));
  1429.     break;
  1430.  
  1431.   case 'k':
  1432.     showKeys = !showKeys;
  1433.     break;
  1434.  
  1435.   case 'p':
  1436.     demoMode = !demoMode;
  1437.     if (demoMode)
  1438.       autoDemo(-999);
  1439.     break;
  1440.  
  1441.   case 'D':
  1442.     debug = !debug;
  1443.     break;
  1444.  
  1445.   case 'd':
  1446.     dumpIds();
  1447.     break;
  1448.  
  1449.   case 'h':
  1450.     if (winId[5] == 0)
  1451.       makeWindow(5);
  1452.     else
  1453.       killWindow(5);
  1454.     break;
  1455.  
  1456.   case 't':
  1457.     ii = idToIndex(glutGetWindow());
  1458.     text[ii] = !text[ii];
  1459.     break;
  1460.  
  1461.   case 'r':
  1462.     trackBall(RESET, 0, 0, 0, 0);
  1463.     break;
  1464.  
  1465.   case 'l':
  1466.     lineWidth += 1;
  1467.     updateAll();
  1468.     break;
  1469.  
  1470.   case 'L':
  1471.     lineWidth -= 1;
  1472.     if (lineWidth < 1)
  1473.       lineWidth = 1;
  1474.     updateAll();
  1475.     break;
  1476.  
  1477.   case '0':
  1478.   case '1':
  1479.   case '2':
  1480.   case '3':
  1481.   case '4':
  1482.   case '6':
  1483.     i = key - '0';
  1484.     winVis[i] = !winVis[i];
  1485.     break;
  1486.  
  1487.   case ')':
  1488.     makeWindow(0);
  1489.     break;
  1490.  
  1491.   case '!':
  1492.     makeWindow(1);
  1493.     break;
  1494.  
  1495.   case '@':
  1496.     makeWindow(2);
  1497.     break;
  1498.  
  1499.   case '#':
  1500.     makeWindow(3);
  1501.     break;
  1502.  
  1503.   }
  1504. }
  1505.  
  1506. /* specialFunc - Special keys callback (F keys, cursor keys
  1507.    etc. */
  1508.  
  1509. void
  1510. specialFunc(int key, int x, int y)
  1511. {
  1512.   if (debug || showKeys)
  1513.     printf("Special key %d\n", key);
  1514.  
  1515.   switch (key) {
  1516.   case GLUT_KEY_PAGE_DOWN:
  1517.     scrollLine += 10;
  1518.     updateHelp();
  1519.     updateText();
  1520.     break;
  1521.  
  1522.   case GLUT_KEY_PAGE_UP:
  1523.     scrollLine -= 10;
  1524.     updateHelp();
  1525.     updateText();
  1526.     break;
  1527.  
  1528.   case GLUT_KEY_DOWN:
  1529.     scrollLine += 1;
  1530.     updateHelp();
  1531.     updateText();
  1532.     break;
  1533.  
  1534.   case GLUT_KEY_UP:
  1535.     scrollLine -= 1;
  1536.     updateHelp();
  1537.     updateText();
  1538.     break;
  1539.  
  1540.   case GLUT_KEY_HOME:
  1541.     scrollLine = 0;
  1542.     updateHelp();
  1543.     updateText();
  1544.     break;
  1545.  
  1546.   case GLUT_KEY_END:
  1547.     scrollLine = 9999;
  1548.     updateHelp();
  1549.     updateText();
  1550.     break;
  1551.  
  1552.   case GLUT_KEY_RIGHT:
  1553.     scrollCol -= 1;
  1554.     updateHelp();
  1555.     updateText();
  1556.     break;
  1557.  
  1558.   case GLUT_KEY_LEFT:
  1559.     scrollCol += 1;
  1560.     updateHelp();
  1561.     updateText();
  1562.     break;
  1563.   }
  1564. }
  1565.  
  1566. /* mouseFunc - Mouse button callback */
  1567.  
  1568. void
  1569. mouseFunc(int button, int state, int x, int y)
  1570. {
  1571.   PR("Mouse button %d, state %d, at pos %d, %d\n", button, state, x, y);
  1572.  
  1573.   trackBall(MOUSEBUTTON, button, state, x, y);
  1574. }
  1575.  
  1576. /* motionFunc - Mouse movement (with a button down) callback */
  1577.  
  1578. void
  1579. motionFunc(int x, int y)
  1580. {
  1581.   PR("Mouse motion at %d, %d\n", x, y);
  1582.  
  1583.   trackBall(MOUSEMOTION, 0, 0, x, y);
  1584.  
  1585.   glutPostRedisplay();
  1586. }
  1587.  
  1588. /* passiveMotionFunc - Mouse movement (with no button down)
  1589.    callback */
  1590.  
  1591. void
  1592. passiveMotionFunc(int x, int y)
  1593. {
  1594.   PR2("Mouse motion at %d, %y\n", x, y);
  1595. }
  1596.  
  1597. /* entryFunc - Window entry event callback */
  1598.  
  1599. void
  1600. entryFunc(int state)
  1601. {
  1602.   int winId = glutGetWindow();
  1603.   PR("Entry event: window id %d (index %d), state %d \n", winId, idToIndex(
  1604.       winId), state);
  1605. }
  1606.  
  1607. /* menuStateFunc - Callback to tell us when menus are popped
  1608.    up/down. */
  1609.  
  1610. int menu_state = GLUT_MENU_NOT_IN_USE;
  1611.  
  1612. void
  1613. menuStateFunc(int state)
  1614. {
  1615.   printf("menu stated = %d\n", state);
  1616.   menu_state = state;
  1617.  
  1618.   if (glutGetWindow() == 0) {
  1619.     PR("menuStateFunc: window invalid\n");
  1620.     return;
  1621.   }
  1622.   PR("Menus are%sin use\n", state == GLUT_MENU_IN_USE ? " " : " not ");
  1623.  
  1624.   if ((state == GLUT_MENU_IN_USE) && menuFreeze)
  1625.     glutIdleFunc(NULL);
  1626.   else if (animation)
  1627.     glutIdleFunc(idleFunc);
  1628. }
  1629.  
  1630. /* timerFunc - General test of global timer */
  1631.  
  1632. void
  1633. timerFunc(int value)
  1634. {
  1635.   PR2("timer callback: value %d\n", value);
  1636.   if (timerOn) {
  1637.     glutTimerFunc(DELAY, timerFunc, 1);
  1638.   }
  1639. }
  1640.  
  1641. #if 0
  1642. /* delayedReinstateMenuStateCallback - Hack to reinstate
  1643.    MenuStateCallback after a while.  */
  1644.  
  1645. void
  1646. delayedReinstateMenuStateCallback(int state)
  1647. {
  1648.   glutMenuStateFunc(menuStateFunc);
  1649. }
  1650.  
  1651. #endif
  1652.  
  1653. /* setInitDisplayMode - update display modes from display mode
  1654.    menu */
  1655.  
  1656. void
  1657. setInitDisplayMode(void)
  1658. {
  1659.   int i;
  1660.  
  1661.   displayMode = 0;
  1662.  
  1663.   for (i = 0; i < MODES; i++) {
  1664.     if (modes[i]) {
  1665.       /* printf("Requesting %s \n", modeNames[i]);  */
  1666.       displayMode |= glutMode[i];
  1667.     }
  1668.   }
  1669.  
  1670.   glutInitDisplayMode(displayMode);
  1671.  
  1672.   createMenu6();
  1673.   if (!glutGet(GLUT_DISPLAY_MODE_POSSIBLE))
  1674.     warning("This display mode not supported\n");
  1675. }
  1676.  
  1677. /* makeWindow - Create one of the windows */
  1678.  
  1679. void
  1680. makeWindow(int index)
  1681. {
  1682.   char str[99];
  1683.  
  1684.   if (winId[index] != 0) {
  1685.     /* warning("Attempt to create window which is already
  1686.        created");  */
  1687.     return;
  1688.   }
  1689.   switch (index) {
  1690.  
  1691.   case 0:              /* ordinary RGB windows  */
  1692.   case 1:
  1693.   case 2:
  1694.   case 3:
  1695.  
  1696.     setInitDisplayMode();
  1697.     glutInitWindowPosition(pos[index][0], pos[index][1]);
  1698.     glutInitWindowSize(size[index][0], size[index][1]);
  1699.     winId[index] = glutCreateWindow(" ");
  1700.     PR("Window %d id = %d \n", index, winId[index]);
  1701.     gfxInit(index);
  1702.  
  1703.     addCallbacks();
  1704.  
  1705.     sprintf(str, "window %d (RGB)", index);
  1706.     glutSetWindowTitle(str);
  1707.     sprintf(str, "icon %d", index);
  1708.     glutSetIconTitle(str);
  1709.     glutSetMenu(menu1);
  1710.     glutAttachMenu(GLUT_RIGHT_BUTTON);
  1711.     break;
  1712.  
  1713.   case 4:              /* subwindow  */
  1714.  
  1715.     setInitDisplayMode();
  1716.     winId[index] = glutCreateSubWindow(winId[0], pos[index][0], pos[index]
  1717.       [1], size[index][0], size[index][1]);
  1718.     PR("Window %d id = %d \n", index, winId[index]);
  1719.     gfxInit(index);
  1720.     glutDisplayFunc(drawScene);
  1721.     glutVisibilityFunc(visible);
  1722.     glutReshapeFunc(reshapeFunc);
  1723.  
  1724.     break;
  1725.  
  1726.   case 5:              /* help window  */
  1727.   case 8:              /* text window  */
  1728.     glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
  1729.     glutInitWindowPosition(pos[index][0], pos[index][1]);
  1730.     glutInitWindowSize(size[index][0], size[index][1]);
  1731.     winId[index] = glutCreateWindow(" ");
  1732.     PR("Window %d id = %d \n", index, winId[index]);
  1733.  
  1734.     /* addCallbacks();  */
  1735.     glutKeyboardFunc(keyFunc);
  1736.     glutSpecialFunc(specialFunc);
  1737.  
  1738.     glClearColor(0.15, 0.15, 0.15, 1.0);
  1739.     glColor3f(1, 1, 1);
  1740.     glMatrixMode(GL_PROJECTION);
  1741.     glLoadIdentity();
  1742.     gluOrtho2D(0, 300, 0, 100);
  1743.     glMatrixMode(GL_MODELVIEW);
  1744.     glLoadIdentity();
  1745.  
  1746.     if (index == 5) {
  1747.       glutDisplayFunc(updateHelp);
  1748.       glutSetWindowTitle("help (RGB) win 5");
  1749.       glutSetIconTitle("help");
  1750.     } else {
  1751.       glutDisplayFunc(updateText);
  1752.       glutSetWindowTitle("text (RGB) win 8");
  1753.       glutSetIconTitle("text");
  1754.     }
  1755.     glutSetMenu(menu1);
  1756.     glutAttachMenu(GLUT_RIGHT_BUTTON);
  1757.     break;
  1758.  
  1759.   case 6:              /* color index window  */
  1760.   case 7:              /* color index window  */
  1761.  
  1762.     glutInitDisplayMode(GLUT_DOUBLE | GLUT_INDEX | GLUT_DEPTH);
  1763.     glutInitWindowPosition(pos[index][0], pos[index][1]);
  1764.     glutInitWindowSize(size[index][0], size[index][1]);
  1765.     winId[index] = glutCreateWindow(" ");
  1766.     PR("Window %d id = %d \n", index, winId[index]);
  1767.  
  1768.     gfxInit(index);
  1769.  
  1770.     addCallbacks();
  1771.  
  1772.     sprintf(str, "window %d (color index)", index);
  1773.     glutSetWindowTitle(str);
  1774.     sprintf(str, "icon %d", index);
  1775.     glutSetIconTitle(str);
  1776.     glutSetMenu(menu1);
  1777.     glutAttachMenu(GLUT_RIGHT_BUTTON);
  1778.     break;
  1779.  
  1780.   }
  1781. }
  1782.  
  1783. /* killWindow - Kill one of the main windows */
  1784.  
  1785. void
  1786. killWindow(int index)
  1787. {
  1788.   int i;
  1789.  
  1790.   if (winId[index] == 0) {
  1791.     /* fprintf(stderr, "Attempt to kill invalid window in
  1792.        killWindow\n");  */
  1793.     return;
  1794.   }
  1795.   PR("Killing win %d\n", index);
  1796.   glutSetWindow(winId[index]);
  1797.  
  1798.   /* Disable all callbacks for safety, although
  1799.      glutDestroyWindow  should do this.  */
  1800.  
  1801.   removeCallbacks();
  1802.  
  1803.   glutDestroyWindow(winId[index]);
  1804.   winId[index] = 0;
  1805.   winVis[index] = FALSE;
  1806.  
  1807. #if 0
  1808.   /* If we reinstate the menu state func here, prog breaks.  So
  1809.      reinstate it a little later.  */
  1810.   glutTimerFunc(MENUDELAY, delayedReinstateMenuStateCallback, 1);
  1811. #endif
  1812.  
  1813.   if (index == 5) {     /* help  */
  1814.     scrollLine = 0;
  1815.     scrollCol = 0;
  1816.   }
  1817.   if (index == 8) {     /* text window  */
  1818.     for (i = 0; textPtr[i] != NULL; i++) {
  1819.       free(textPtr[i]); /* free the text strings  */
  1820.       textPtr[i] = NULL;
  1821.     }
  1822.   }
  1823. }
  1824.  
  1825. /* addCallbacks - Add some standard callbacks after creating a
  1826.    window */
  1827.  
  1828. void
  1829. addCallbacks(void)
  1830. {
  1831.   glutDisplayFunc(drawScene);
  1832.   glutVisibilityFunc(visible);
  1833.   glutReshapeFunc(reshapeFunc);
  1834.   glutKeyboardFunc(keyFunc);
  1835.   glutSpecialFunc(specialFunc);
  1836.   glutMouseFunc(mouseFunc);
  1837.   glutMotionFunc(motionFunc);
  1838.   glutEntryFunc(entryFunc);
  1839.  
  1840. /* Callbacks for exotic input devices. Must get my dials &
  1841.    buttons back. */
  1842.  
  1843.   glutSpaceballMotionFunc(spaceballMotionCB);
  1844.   glutSpaceballRotateFunc(spaceballRotateCB);
  1845.   glutSpaceballButtonFunc(spaceballButtonCB);
  1846.  
  1847.   glutButtonBoxFunc(buttonBoxCB);
  1848.   glutDialsFunc(dialsCB);
  1849.  
  1850.   glutTabletMotionFunc(tabletMotionCB);
  1851.   glutTabletButtonFunc(tabletButtonCB);
  1852. }
  1853.  
  1854. /* removeCallbacks - Remove all callbacks before destroying a
  1855.    window. GLUT probably does this  anyway but we'll be safe. */
  1856.  
  1857. void
  1858. removeCallbacks(void)
  1859. {
  1860.   glutVisibilityFunc(NULL);
  1861.   glutReshapeFunc(NULL);
  1862.   glutKeyboardFunc(NULL);
  1863.   glutSpecialFunc(NULL);
  1864.   glutMouseFunc(NULL);
  1865.   glutMotionFunc(NULL);
  1866.   glutEntryFunc(NULL);
  1867. }
  1868.  
  1869. /* updateHelp - Update the help window after user scrolls. */
  1870.  
  1871. void
  1872. updateHelp(void)
  1873. {
  1874.   static char *helpPtr[] =
  1875.   {
  1876.     "(Use PGUP, PGDN, HOME, END, arrows to scroll help text)          ",
  1877.     "                                                                ",
  1878.     "A demo program for GLUT.                                        ",
  1879.     "G Edwards, Aug 95                                               ",
  1880.     "Exercises 99% of GLUT calls                                     ",
  1881.     VERSIONLONG,
  1882.     "                                                                ",
  1883.     "This text uses GLUT_STROKE_MONO_ROMAN font, a built-in vector font.",
  1884.     "(Try resizing the help window).                                 ",
  1885.     "                                                                ",
  1886.     "Keys:                                                           ",
  1887.     " esc   quit                                                     ",
  1888.     " t     toggle text on/off in each window                        ",
  1889.     " h     toggle help                                              ",
  1890.     " q     quit current window                                      ",
  1891.     " a     auto demo                                                ",
  1892.     " p     pause/unpause demo                                       ",
  1893.     " l     increase line width (gfx & stroke text)                  ",
  1894.     " L     decrease line width (gfx & stroke text)                  ",
  1895.     " r     reset transforms                                         ",
  1896.     " k     show keyboard events                                     ",
  1897.     " D     show all events                                          ",
  1898.     "                                                                ",
  1899.     "Mouse:                                                          ",
  1900.     " Left button:    rotate                                         ",
  1901.     " Middle button:  pan                                            ",
  1902.     " Left + middle:  zoom                                           ",
  1903.     NULL};
  1904.  
  1905.   updateScrollWindow(5, helpPtr);
  1906. }
  1907.  
  1908. /* updateText - Update a text window */
  1909.  
  1910. void
  1911. updateText(void)
  1912. {
  1913.   int i;
  1914.  
  1915.   if (textPtr[0] == NULL) {
  1916.     for (i = 0; i < 20; i++) {
  1917.       textPtr[i] = (char *) malloc(50);
  1918.       strcpy(textPtr[i], "no current text");
  1919.     }
  1920.     textPtr[20] = NULL;
  1921.   }
  1922.   updateScrollWindow(8, textPtr);
  1923. }
  1924.  
  1925. /* updateScrollWindow */
  1926.  
  1927. void
  1928. updateScrollWindow(int index, char **ptr)
  1929. {
  1930.   int i, j, lines = 0;
  1931.  
  1932.   if (winId[index] == 0)
  1933.     return;
  1934.  
  1935.   glutSetWindow(winId[index]);
  1936.  
  1937.   for (i = 0; ptr[i] != NULL; i++)
  1938.     lines++;
  1939.  
  1940.   if (scrollLine < 0)
  1941.     scrollLine = 0;
  1942.   if (scrollLine > (lines - 5))
  1943.     scrollLine = lines - 5;
  1944.  
  1945.   glClear(GL_COLOR_BUFFER_BIT);
  1946.  
  1947.   glLineWidth(lineWidth);
  1948.  
  1949.   for (i = scrollLine, j = 1; ptr[i] != NULL; i++, j++)
  1950.     strokeString(scrollCol * 50, 100 - j * 6, ptr[i],
  1951.       GLUT_STROKE_MONO_ROMAN);
  1952.  
  1953.   glutSwapBuffers();
  1954.  
  1955. }
  1956.  
  1957. /* updateAll - Update all visible windows after soem global
  1958.    change, eg. line width */
  1959.  
  1960. void
  1961. updateAll(void)
  1962. {
  1963.   int i;
  1964.  
  1965.   if (winId[5] != 0)
  1966.     updateHelp();
  1967.  
  1968.   if (winId[8] != 0)
  1969.     updateText();
  1970.  
  1971.   for (i = 0; i < MAXWIN; i++)
  1972.     if (winId[i]) {
  1973.       glutSetWindow(winId[i]);
  1974.       glutPostRedisplay();
  1975.     }
  1976. }
  1977.  
  1978. /* idToIndex - Convert GLUT window id to our internal index */
  1979.  
  1980. int
  1981. idToIndex(int id)
  1982. {
  1983.   int i;
  1984.   for (i = 0; i < MAXWIN; i++) {
  1985.     if (winId[i] == id)
  1986.       return i;
  1987.   }
  1988.   fprintf(stderr, "error: id %d not found \n", id);
  1989.   return (-1);
  1990. }
  1991.  
  1992. /* warning - warning messages */
  1993.  
  1994. void
  1995. warning(char *msg)
  1996. {
  1997.   fprintf(stderr, "\007");
  1998.  
  1999.   if (debug) {
  2000.     fprintf(stderr, "%s", msg);
  2001.     if (msg[strlen(msg)] != '\n')
  2002.       fprintf(stderr, "%s", "\n");
  2003.   }
  2004. }
  2005.  
  2006. /* dumpIds - Debug: dump some internal data  */
  2007.  
  2008. void
  2009. dumpIds(void)
  2010. {
  2011.   int i, j;
  2012.  
  2013.   printf("\nInternal data:\n");
  2014.  
  2015.   for (i = 0; i < MAXWIN; i++)
  2016.     printf("Index %d, glut win id %d, visibility %d\n", i, winId[i],
  2017.       winVis[i]);
  2018.  
  2019.   for (i = 0; i < MAXWIN; i++) {
  2020.     if (winId[i])
  2021.       glutSetWindow(winId[i]);
  2022.     else {
  2023.       printf("index %d - no glut window\n", i);
  2024.       continue;
  2025.     }
  2026.  
  2027.     for (j = 1; j <= MAXWIN; j++)
  2028.       printf("Index %d, display list %d %s defined\n", i, j, glIsList(j) ?
  2029.         "is " : "not");
  2030.   }
  2031. }
  2032.  
  2033. /* autoDemo - Run auto demo/test This is a bit tricky. We need
  2034.    to start a timer sequence which progressively orders things
  2035.    to be done. The work really gets done when we return from
  2036.    our callback. Have to think about the event loop / callback
  2037.    design here. */
  2038.  
  2039. void
  2040. autoDemo(int value)
  2041. {
  2042.  
  2043. #define STEP(a, b)  \
  2044.     case a:         \
  2045.         action(a);  \
  2046.     glutTimerFunc(AUTODELAY * b, autoDemo, next(a); \
  2047.     break;
  2048.  
  2049.   static int index = 0;
  2050.   static int count = 0;
  2051.   static int restartValue = -2;
  2052.  
  2053.   if (value == -999)
  2054.     value = restartValue;
  2055.  
  2056.   restartValue = value;
  2057.  
  2058. #define AUTODELAY2 AUTODELAY*0.66
  2059.  
  2060.   /* fprintf(stderr, "autoDemo: value %d \n", value);  */
  2061.  
  2062.   if (!demoMode)
  2063.     return;
  2064.  
  2065.   if (menu_state == GLUT_MENU_IN_USE) {
  2066.     glutTimerFunc(AUTODELAY / 2, autoDemo, value);
  2067.     return;
  2068.   }
  2069.   switch (value) {
  2070.  
  2071. /* Entry point; kill off existing windows. */
  2072.  
  2073.   case -2:
  2074.     killAllWindows();
  2075.     glutTimerFunc(AUTODELAY / 2, autoDemo, 1);
  2076.     break;
  2077.  
  2078. /* Start making windows */
  2079.  
  2080.   case -1:
  2081.     makeWindow(0);
  2082.     glutTimerFunc(AUTODELAY, autoDemo, 0);  /* skip case 0
  2083.                                                first time  */
  2084.     break;
  2085.  
  2086. /* Change shape & backdrop */
  2087.  
  2088.   case 0:
  2089.     currentShape = (currentShape + 1) % 9;
  2090.     redefineShapes(currentShape);
  2091.     count += 1;
  2092.     if (count % 2)
  2093.       backdrop = !backdrop;
  2094.     glutTimerFunc(AUTODELAY, autoDemo, 1);
  2095.     break;
  2096.  
  2097. /* Keep making windows */
  2098.  
  2099.   case 1:
  2100.     makeWindow(1);
  2101.     glutTimerFunc(AUTODELAY, autoDemo, 2);
  2102.     break;
  2103.  
  2104.   case 2:
  2105.     makeWindow(2);
  2106.     glutTimerFunc(AUTODELAY, autoDemo, 3);
  2107.     break;
  2108.  
  2109.   case 3:
  2110.     makeWindow(3);
  2111.     glutTimerFunc(AUTODELAY, autoDemo, 4);
  2112.     break;
  2113.  
  2114.   case 4:
  2115.     makeWindow(4);
  2116.     glutTimerFunc(AUTODELAY, autoDemo, 5);
  2117.     break;
  2118.  
  2119.   case 5:
  2120.     makeWindow(5);
  2121.     glutTimerFunc(AUTODELAY * 2, autoDemo, 51);
  2122.     break;
  2123.  
  2124.   case 51:
  2125.     makeWindow(6);
  2126.     glutTimerFunc(AUTODELAY * 2, autoDemo, 52);
  2127.     break;
  2128.  
  2129.   case 52:
  2130.     makeWindow(7);
  2131.     glutTimerFunc(AUTODELAY * 2, autoDemo, 53);
  2132.     break;
  2133.  
  2134. /* Kill last 3 windows, leave 4 up. */
  2135.  
  2136.   case 53:
  2137.     killWindow(7);
  2138.     glutTimerFunc(AUTODELAY, autoDemo, 54);
  2139.     break;
  2140.  
  2141.   case 54:
  2142.     killWindow(6);
  2143.     glutTimerFunc(AUTODELAY, autoDemo, 6);
  2144.     break;
  2145.  
  2146.   case 6:
  2147.     killWindow(5);
  2148.     glutTimerFunc(AUTODELAY, autoDemo, 7);
  2149.     break;
  2150.  
  2151.   case 7:
  2152.     killWindow(4);
  2153.     glutTimerFunc(AUTODELAY, autoDemo, 700);
  2154.     break;
  2155.  
  2156. /* Change shape again */
  2157.  
  2158.   case 700:
  2159.     currentShape = (currentShape + 1) % 9;
  2160.     redefineShapes(currentShape);
  2161.     glutTimerFunc(AUTODELAY, autoDemo, 701);
  2162.     break;
  2163.  
  2164. /* Cycle 4 main windows through various window ops.  */
  2165.  
  2166.   case 701:
  2167.     positionWindow(index);
  2168.     index = (index + 1) % 4;
  2169.     glutTimerFunc(AUTODELAY2, autoDemo, index > 0 ? 701 : 702);
  2170.     break;
  2171.  
  2172.   case 702:
  2173.     reshapeWindow(index);
  2174.     index = (index + 1) % 4;
  2175.     glutTimerFunc(AUTODELAY2, autoDemo, index > 0 ? 702 : 703);
  2176.     break;
  2177.  
  2178.   case 703:
  2179.     iconifyWindow(index);
  2180.     index = (index + 1) % 4;
  2181.     glutTimerFunc(AUTODELAY2, autoDemo, index > 0 ? 703 : 704);
  2182.     break;
  2183.  
  2184.   case 704:
  2185.     showWindow(index);
  2186.     index = (index + 1) % 4;
  2187.     glutTimerFunc(AUTODELAY2, autoDemo, index > 0 ? 704 : 705);
  2188.     break;
  2189.  
  2190.   case 705:
  2191.     hideWindow(index);
  2192.     index = (index + 1) % 4;
  2193.     glutTimerFunc(AUTODELAY2, autoDemo, index > 0 ? 705 : 706);
  2194.     break;
  2195.  
  2196.   case 706:
  2197.     showWindow(index);
  2198.     index = (index + 1) % 4;
  2199.     glutTimerFunc(AUTODELAY2, autoDemo, index > 0 ? 706 : 707);
  2200.     break;
  2201.  
  2202.   case 707:
  2203.     pushWindow(index);
  2204.     index = (index + 1) % 4;
  2205.     glutTimerFunc(AUTODELAY2, autoDemo, index > 0 ? 707 : 708);
  2206.     break;
  2207.  
  2208.   case 708:
  2209.     popWindow(index);
  2210.     index = (index + 1) % 4;
  2211.     glutTimerFunc(AUTODELAY2, autoDemo, index > 0 ? 708 : 8);
  2212.     break;
  2213.  
  2214. /* Kill all windows */
  2215.  
  2216.   case 8:
  2217.     killWindow(3);
  2218.     glutTimerFunc(AUTODELAY, autoDemo, 9);
  2219.     break;
  2220.  
  2221.   case 9:
  2222.     killWindow(2);
  2223.     glutTimerFunc(AUTODELAY, autoDemo, 10);
  2224.     break;
  2225.  
  2226.   case 10:
  2227.     killWindow(1);
  2228.     glutTimerFunc(AUTODELAY, autoDemo, 11);
  2229.     break;
  2230.  
  2231.   case 11:
  2232.     killWindow(0);
  2233.     glutTimerFunc(AUTODELAY, autoDemo, -1);  /* back to start  */
  2234.     break;
  2235.   }
  2236.  
  2237. }
  2238.  
  2239. /* attachMenus - Attach/detach menus to/from mouse buttons */
  2240.  
  2241. void
  2242. attachMenus(void)
  2243. {
  2244.   int i, b;
  2245.   int button[3] =
  2246.   {GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON, GLUT_RIGHT_BUTTON};
  2247.  
  2248.   for (i = 0; i < MAXWIN; i++) {
  2249.     if (winId[i] != 0) {
  2250.       for (b = 0; b < 3; b++) {
  2251.         glutSetWindow(winId[i]);
  2252.         glutSetMenu(menu1);
  2253.         if (menuButton[b])
  2254.           glutAttachMenu(button[b]);
  2255.         else
  2256.           glutDetachMenu(button[b]);
  2257.       }
  2258.     }
  2259.   }
  2260. }
  2261.  
  2262. /* killAllWindows - Kill all windows (except 0) */
  2263.  
  2264. void
  2265. killAllWindows(void)
  2266. {
  2267.   int w;
  2268.  
  2269.   for (w = 1; w < MAXWIN; w++)
  2270.     if (winId[w])
  2271.       killWindow(w);
  2272. }
  2273.  
  2274. /* makeAllWindows - Make all windows */
  2275.  
  2276. void
  2277. makeAllWindows(void)
  2278. {
  2279.   int w;
  2280.  
  2281.   for (w = 0; w < MAXWIN; w++)
  2282.     if (!winId[w])
  2283.       makeWindow(w);
  2284. }
  2285.  
  2286. /* checkArgs - Check command line args */
  2287.  
  2288. void
  2289. checkArgs(int argc, char *argv[])
  2290. {
  2291.   int argp;
  2292.   Boolean quit = FALSE;
  2293.   Boolean error = FALSE;
  2294.  
  2295. #define AA argv[argp]
  2296.  
  2297. #if 0
  2298. #define NEXT argp++;      \
  2299.         if(argp >= argc) \
  2300.         {                \
  2301.            Usage();      \
  2302.            Exit(1);      \
  2303.         }
  2304. #endif
  2305.  
  2306.   argp = 1;
  2307.   while (argp < argc) {
  2308.     if (match(AA, "-help")) {
  2309.       commandLineHelp();
  2310.       quit = TRUE;
  2311.     } else if (match(AA, "-version")) {
  2312.       printf(VERSIONLONG "\n");
  2313.       quit = TRUE;
  2314.     } else if (match(AA, "-auto")) {
  2315.       demoMode = TRUE;
  2316.     } else if (match(AA, "-scale")) {
  2317.       argp++;
  2318.       scaleFactor = atof(argv[argp]);
  2319.     } else {
  2320.       fprintf(stderr, "Unknown arg: %s\n", AA);
  2321.       error = TRUE;
  2322.       quit = TRUE;
  2323.     }
  2324.     argp++;
  2325.   }
  2326.  
  2327.   if (error) {
  2328.     commandLineHelp();
  2329.     exit(1);
  2330.   }
  2331.   if (quit)
  2332.     exit(0);
  2333. }
  2334.  
  2335. /* commandLineHelp - Command line help */
  2336.  
  2337. void
  2338. commandLineHelp(void)
  2339. {
  2340.   printf("Usage:\n");
  2341.   printf(" -h[elp]            this stuff\n");
  2342.   printf(" -v[ersion]         show version\n");
  2343.   printf(" -a[uto]            start in auto demo mode\n");
  2344.   printf(" -s[cale] f         scale windows by f\n");
  2345.   printf("Standard GLUT args:\n");
  2346.   printf(" -iconic            start iconic\n");
  2347.   printf(" -display DISP      use display DISP\n");
  2348.   printf(" -direct            use direct rendering (default)\n");
  2349.   printf(" -indirect          use indirect rendering\n");
  2350.   printf(" -sync              use synchronous X protocol\n");
  2351.   printf(" -gldebug           check OpenGL errors\n");
  2352.   printf(" -geometry WxH+X+Y  standard X window spec (overridden here) \n");
  2353. }
  2354.  
  2355. /* match - Match a string (any unique substring). */
  2356.  
  2357. Boolean
  2358. match(char *arg, char *t)
  2359. {
  2360.   if (strstr(t, arg))
  2361.     return TRUE;
  2362.   else
  2363.     return FALSE;
  2364. }
  2365.  
  2366. /* scaleWindows - Scale initial window sizes ansd positions */
  2367.  
  2368. void
  2369. scaleWindows(float scale)
  2370. {
  2371.   int i;
  2372.  
  2373.   for (i = 0; i < MAXWIN; i++) {
  2374.     pos[i][0] = pos[i][0] * scale;
  2375.     pos[i][1] = pos[i][1] * scale;
  2376.     size[i][0] = size[i][0] * scale;
  2377.     size[i][1] = size[i][1] * scale;
  2378.   }
  2379. }
  2380.  
  2381. /* trackBall - A simple trackball (not with proper rotations). */
  2382.  
  2383. /** A simple trackball with spin = left button
  2384.                            pan  = middle button
  2385.                            zoom = left + middle
  2386.    Doesn't have proper trackball rotation, ie axes which remain fixed in
  2387.    the scene. We should use the trackball code from 4Dgifts. */
  2388.  
  2389. #define STARTROTATE(x, y)     \
  2390. {                             \
  2391.     startMX = x;              \
  2392.     startMY = y;              \
  2393. }
  2394.  
  2395. #define STOPROTATE(x, y)      \
  2396. {                             \
  2397.     steadyXangle = varXangle; \
  2398.     steadyYangle = varYangle; \
  2399. }
  2400.  
  2401. #define STARTPAN(x, y)        \
  2402. {                             \
  2403.     startMX = x;              \
  2404.     startMY = y;              \
  2405. }
  2406.  
  2407. #define STOPPAN(x, y)         \
  2408. {                             \
  2409.     steadyX = varX;           \
  2410.     steadyY = varY;           \
  2411. }
  2412.  
  2413. #define STARTZOOM(x, y)       \
  2414. {                             \
  2415.     startMX = x;              \
  2416.     startMY = y;              \
  2417. }
  2418.  
  2419. #define STOPZOOM(x, y)        \
  2420. {                             \
  2421.     steadyZ = varZ;           \
  2422. }
  2423.  
  2424. void
  2425. trackBall(int mode, int button, int state, int x, int y)
  2426. {
  2427.   static int startMX = 0, startMY = 0;  /* initial mouse pos  */
  2428.   static int deltaMX = 0, deltaMY = 0;  /* initial mouse pos  */
  2429.   static float steadyXangle = 0.0, steadyYangle = 0.0;
  2430.   static float varXangle = 0.0, varYangle = 0.0;
  2431.   static float steadyX = 0.0, steadyY = 0.0, steadyZ = 0.0;
  2432.   static float varX = 0.0, varY = 0.0, varZ = 0.0;
  2433.  
  2434.   switch (mode) {
  2435.  
  2436.   case RESET:
  2437.     steadyXangle = steadyYangle = steadyX = steadyY = steadyZ = 0.0;
  2438.     break;
  2439.  
  2440.   case MOUSEBUTTON:
  2441.  
  2442.     if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN && !middleDown) {
  2443.       STARTROTATE(x, y);
  2444.       leftDown = TRUE;
  2445.     } else if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN &&
  2446.       middleDown) {
  2447.       STOPPAN(x, y);
  2448.       STARTZOOM(x, y);
  2449.       leftDown = TRUE;
  2450.     } else if (button == GLUT_MIDDLE_BUTTON && state == GLUT_DOWN &&
  2451.       !leftDown) {
  2452.       STARTPAN(x, y);
  2453.       middleDown = TRUE;
  2454.     } else if (button == GLUT_MIDDLE_BUTTON && state == GLUT_DOWN &&
  2455.       leftDown) {
  2456.       STOPROTATE(x, y);
  2457.       STARTZOOM(x, y);
  2458.       middleDown = TRUE;
  2459.     } else if (state == GLUT_UP && button == GLUT_LEFT_BUTTON && !middleDown) {
  2460.       STOPROTATE(x, y);
  2461.       leftDown = FALSE;
  2462.     } else if (state == GLUT_UP && button == GLUT_LEFT_BUTTON && middleDown) {
  2463.       STOPZOOM(x, y);
  2464.       STARTROTATE(x, y);
  2465.       leftDown = FALSE;
  2466.     } else if (state == GLUT_UP && button == GLUT_MIDDLE_BUTTON && !leftDown) {
  2467.       STOPPAN(x, y);
  2468.       middleDown = FALSE;
  2469.     } else if (state == GLUT_UP && button == GLUT_MIDDLE_BUTTON && leftDown) {
  2470.       STOPZOOM(x, y);
  2471.       STARTROTATE(x, y);
  2472.       middleDown = FALSE;
  2473.     }
  2474.     break;
  2475.  
  2476.   case APPLY:
  2477.  
  2478.     if (leftDown && !middleDown) {
  2479.       glTranslatef(steadyX, steadyY, steadyZ);
  2480.       glRotatef(varXangle, 0, 1, 0);
  2481.       glRotatef(varYangle, 1, 0, 0);
  2482.     }
  2483.     /* Middle button pan  */
  2484.  
  2485.     else if (middleDown && !leftDown) {
  2486.       glTranslatef(varX, varY, steadyZ);
  2487.       glRotatef(steadyXangle, 0, 1, 0);
  2488.       glRotatef(steadyYangle, 1, 0, 0);
  2489.     }
  2490.     /* Left + middle zoom.  */
  2491.  
  2492.     else if (leftDown && middleDown) {
  2493.       glTranslatef(steadyX, steadyY, varZ);
  2494.       glRotatef(steadyXangle, 0, 1, 0);
  2495.       glRotatef(steadyYangle, 1, 0, 0);
  2496.     }
  2497.     /* Nothing down.  */
  2498.  
  2499.     else {
  2500.       glTranslatef(steadyX, steadyY, steadyZ);
  2501.       glRotatef(steadyXangle, 0, 1, 0);
  2502.       glRotatef(steadyYangle, 1, 0, 0);
  2503.     }
  2504.     break;
  2505.  
  2506.   case MOUSEMOTION:
  2507.  
  2508.     deltaMX = x - startMX;
  2509.     deltaMY = startMY - y;
  2510.  
  2511.     if (leftDown && !middleDown) {
  2512.       varXangle = steadyXangle + deltaMX;
  2513.       varYangle = steadyYangle + deltaMY;
  2514.     } else if (middleDown && !leftDown) {
  2515.       varX = steadyX + deltaMX / 100.0;
  2516.       varY = steadyY + deltaMY / 100.0;
  2517.     } else if (leftDown && middleDown) {
  2518.       varZ = steadyZ - deltaMY / 50.0;
  2519.     }
  2520.     break;
  2521.   }
  2522.  
  2523. }
  2524.  
  2525. /* Callbacks for exotic input devices. These have not been
  2526.    tested yet owing to the usual complete absence of such
  2527.    devices in the UK support group. */
  2528.  
  2529. /* spaceballMotionCB */
  2530.  
  2531. void
  2532. spaceballMotionCB(int x, int y, int z)
  2533. {
  2534.   printf("spaceballMotionCB: translations are X %d, Y %d, Z %d\n", x, y, z);
  2535. }
  2536.  
  2537. /* spaceballRotateCB */
  2538.  
  2539. void
  2540. spaceballRotateCB(int x, int y, int z)
  2541. {
  2542.   printf("spaceballRotateCB: rotations are X %d, Y %d, Z %d\n", x, y, z);
  2543. }
  2544.  
  2545. /* spaceballButtonCB */
  2546.  
  2547. void
  2548. spaceballButtonCB(int button, int state)
  2549. {
  2550.   printf("spaceballButtonCB: button %d, state %d\n", button, state);
  2551. }
  2552.  
  2553. /* buttonBoxCB */
  2554.  
  2555. void
  2556. buttonBoxCB(int button, int state)
  2557. {
  2558.   printf("buttonBoxCB: button %d, state %d\n", button, state);
  2559. }
  2560.  
  2561. /* dialsCB */
  2562.  
  2563. void
  2564. dialsCB(int dial, int value)
  2565. {
  2566.   printf("dialsCB: dial %d, value %d\n", dial, value);
  2567. }
  2568.  
  2569. /* tabletMotionCB */
  2570.  
  2571. void
  2572. tabletMotionCB(int x, int y)
  2573. {
  2574.   printf("tabletMotionCB: X %d, Y %d\n", x, y);
  2575. }
  2576.  
  2577. /* tabletButtonCB */
  2578.  
  2579. void
  2580. tabletButtonCB(int button, int state, int dummy1, int dummy2)
  2581. {
  2582.   printf("tabletButtonCB: button %d, state %d\n", button, state);
  2583. }
  2584.